#include <iostream>

#include "readxml.h"

using namespace std;


Readxml::Readxml()
{
}

TiXmlDocument *Readxml::readDoc(const char *pXmlPath)
{
    TiXmlDocument *pDoc = new(std::nothrow) TiXmlDocument(pXmlPath);
    if(nullptr == pDoc)
    {
        cout<<"xml is nullptr"<<endl;
        return nullptr;
    }

    if(!pDoc->LoadFile())
    {
        cout<<"read failed!"<<endl;
        delete pDoc;
        return nullptr;
    }    

    return pDoc;
}

TiXmlNode* Readxml::selectSingleNode(string strNodeName, string strNodeAttrName, string strNodeAttrValue, TiXmlDocument *pDoc)
{
    TiXmlElement *pRootElement = pDoc->RootElement();
    if(nullptr == pRootElement)
    {
        cout << "Parsing error can't get root" << endl;
        return nullptr;
    }

    TiXmlNode *pSelectNode = nullptr;

    for(TiXmlNode *pNode=pRootElement->FirstChildElement(); pNode != nullptr; pNode = pNode->NextSiblingElement())
    {
        pSelectNode = selectChildNode(pNode, strNodeName, strNodeAttrName, strNodeAttrValue);
        if(pSelectNode != nullptr)
        {
            break;
        }
    }

    if(pSelectNode != nullptr)
    {
        return pSelectNode;
    }
    else
    {
        cout << "Parsing error, unable to get node " << strNodeName.c_str() << endl;
        return nullptr;
    }
}

TiXmlNode *Readxml::selectSingleNode(string strNodeName, TiXmlDocument *pDoc)
{
    TiXmlElement *pRootElement = pDoc->RootElement();
    if(nullptr == pRootElement)
    {
        cout << "Parsing error can't get root" << endl;
        return nullptr;
    }

    TiXmlNode * pSelectNode = nullptr;

    for(TiXmlNode *pNode = pRootElement->FirstChildElement(); pNode != nullptr; pNode = pNode->NextSiblingElement())
    {
        pSelectNode = selectChildNode(pNode,strNodeName);
        if(pSelectNode != nullptr)
        {
            break;
        }
    }

    if(pSelectNode != nullptr)
    {
        return pSelectNode;
    }
    else
    {
        cout << "Parsing error, unable to get node " << strNodeName.c_str() << endl;
        return nullptr;
    }
}

//std::vector<TiXmlNode*> getNodeVec(TiXmlDocument *pDoc, const char *pNodeName); //对应参数：1.读取后xml 2.节点名称
//static std::vector<TiXmlNode*> getNodeVec(TiXmlDocument *pDoc, const char *pNodeName, TiXmlNode *pParentNode); //1.读取后xml 2.父节点的名字
std::vector<TiXmlNode*> Readxml::getNodeVec(TiXmlDocument* pDoc, const char *pNodeName)
{
    //获得根元素
    TiXmlElement *pRootElement = pDoc->RootElement();

    vector<TiXmlNode *> vecNode = vector<TiXmlNode *>();

    for(TiXmlNode *pNode = pRootElement->FirstChildElement(); pNode != nullptr; pNode = pNode->NextSiblingElement())
    {
        insertNodeVec(pNode, pNodeName, vecNode);
    }

    return vecNode;
}

std::vector<TiXmlNode *> Readxml::getNodeVec(TiXmlDocument *pDoc, const char *pNodeName, TiXmlNode *pParentNode)
{
    vector<TiXmlNode*> vecNode = vector<TiXmlNode*>();

    for(TiXmlNode *pNode = pParentNode->FirstChildElement(); pNode != nullptr; pNode = pNode->NextSiblingElement())
    {
        insertNodeVec(pNode, pNodeName, vecNode);
    }

    return vecNode;
}

vector<TiXmlNode*> Readxml::getSelectNodeVec(TiXmlDocument* pDoc, const char *pNodeName, TiXmlNode* selectNode)
{
    vector<TiXmlNode*> vecNode;

    for(TiXmlNode *pNode = selectNode->FirstChildElement(); pNode != nullptr; pNode = pNode->NextSiblingElement())
    {
        insertNodeVec(pNode, pNodeName, vecNode);
    }

    return vecNode;
}

bool Readxml::addSingleNode(TiXmlNode *pNode, const char* pNodeName, TiXmlDocument *pDoc, map<const char*, const char*> mapAttr)
{
    //获得xml的头，即声明部分
    TiXmlDeclaration *pDecl = pDoc->FirstChild()->ToDeclaration();
    if(pDecl != nullptr)
    {
        cout << "xml version:" << pDecl->Version()  << endl;
        cout << "xml Format encoding:" << pDecl->Encoding() << endl;
    }

    //获得根元素
    TiXmlElement *pRootElement = pDoc->RootElement();
    if(pRootElement != nullptr)
    {
        TiXmlElement *pNewElement = new TiXmlElement(pNodeName);
        pNode->LinkEndChild(pNewElement);

        for(auto &iter: mapAttr)
        {
            pNewElement->SetAttribute(iter.first, iter.second);
        }

        if(pDoc->SaveFile())
        {
            cout << "Added successfully" << endl;
            return true;
        }
        else
        {
            cout << "add failed" << endl;
            return false;
        }
    }
    else
    {
        return false;
    }
}

bool Readxml::addNoAttrNode(TiXmlNode *pNode, const char *pNodeName, TiXmlDocument *pDoc)
{
    //获得根元素
    TiXmlElement *pRootElement = pDoc->RootElement();
    if(pRootElement != nullptr)
    {
        TiXmlElement *pNewElement = new TiXmlElement(pNodeName);
        pNode->LinkEndChild(pNewElement);

        if(pDoc->SaveFile())
        {
            cout << "Added successfully" << endl;
            return true;
        }
        else
        {
            cout << "Add failed" << endl;
            return false;
        }
    }
    else
    {
        return false;
    }
}

TiXmlNode *Readxml::addNoAttrNodeAndReturn(TiXmlNode *pNode, const char *pNodeName, TiXmlDocument *pDoc)
{
    TiXmlElement *pRootElement = pDoc->RootElement();
    if(pRootElement != nullptr)
    {
        TiXmlElement *pNewElement = new TiXmlElement(pNodeName);
        pNode->LinkEndChild(pNewElement);

        if(pDoc->SaveFile())
        {
            cout << "Added successfully" << endl;
            return pNewElement;
        }
        else
        {
            cout << "Add failed" << endl;
            return nullptr;
        }
    }
    else
    {
        return nullptr;
    }
}

void  Readxml::insertNodeVec(TiXmlNode *pNode, const char *pNodeName, vector<TiXmlNode*> &vecNode)
{
    if(pNode == nullptr)
    {
        cout << "Node is null" << endl;
        return;
    }

    switch(pNode->Type())
    {
        //节点类型是Element
    case TiXmlText::TINYXML_ELEMENT:
    {

        if(0 == strcmp(pNodeName, pNode->Value()))
        {
            vecNode.push_back(pNode);
        }

        for(TiXmlNode *pChildNode = pNode->FirstChild(); pChildNode != nullptr; pChildNode = pChildNode->NextSibling())
        {
            insertNodeVec(pChildNode, pNodeName, vecNode);
        }

        break;
    }

    case TiXmlText::TINYXML_DOCUMENT:
    case TiXmlText::TINYXML_COMMENT:
    case TiXmlText::TINYXML_UNKNOWN:
    case TiXmlText::TINYXML_DECLARATION:
    case TiXmlText::TINYXML_TYPECOUNT:
    {
        break;//Nothing to do
    }

    default:
    {
        break;
    }

    }
}

bool Readxml::delSingleNode(TiXmlNode *pNode, TiXmlDocument *pDoc)
{
    TiXmlElement *pRootElement = pDoc->RootElement();
    if(pRootElement != nullptr)
    {
        if(pRootElement == pNode)
        {
            if(pDoc->RemoveChild(pRootElement))
            {
                return pDoc->SaveFile();
            }
            else
            {
                return false;
            }
        }

        if(nullptr != pNode)
        {
            TiXmlNode *pNode = pNode->Parent();
            if (nullptr == pNode)
            {
                cout<<"Parent Node is nullptr"<<endl;
                return false;
            }
            else
            {
                if(pNode->RemoveChild(pNode))
                {
                    return pDoc->SaveFile();
                }
                else
                {
                    cout<<"Del false"<<endl;
                    return false;
                }
            }
        }
        else
        {
            return false;
        }
    }

    return false;
}

TiXmlNode *Readxml::selectChildNode(TiXmlNode *pNode, string strNodeName)
{
    if(nullptr == pNode)
    {
        return nullptr;
    }

    TiXmlNode *pSelectedNode = nullptr;
    TiXmlNode *pChildNode = nullptr;

    switch (pNode->Type())
    {
    case TiXmlText::TINYXML_DOCUMENT:
    case TiXmlText::TINYXML_DECLARATION:
    case TiXmlText::TINYXML_TEXT:
    case TiXmlText::TINYXML_UNKNOWN:
    case TiXmlText::TINYXML_COMMENT:
    {
        break;
    }

    case TiXmlText::TINYXML_ELEMENT:
    {
        if(pNode->Value() == strNodeName)
        {
            return pNode;
        }
        else
        {
            //循环访问它的每一个元素
            for(pChildNode = pNode->FirstChild(); pChildNode != nullptr; pChildNode = pChildNode->NextSibling())
            {
                pSelectedNode = selectChildNode(pChildNode, strNodeName);
                if(pSelectedNode != nullptr)
                {
                    return pSelectedNode;
                }
            }
        }
    }

    default:
    {
        break;
    }

    }

    return nullptr;
}

//    static TiXmlNode* selectChildNode(TiXmlNode *pNode, std::string strNodeName, std::string strNodeAttrName, std::string strNodeAttrValue);
TiXmlNode *Readxml::selectChildNode(TiXmlNode *pNode, string strNodeName, string strNodeAttrName, string strNodeAttrValue)
{
    if(nullptr == pNode)
    {
        return nullptr;
    }

    TiXmlNode *pSelectedNode = nullptr;
    TiXmlNode *pChildNode = nullptr;

    switch (pNode->Type())
    {
    case TiXmlText::TINYXML_DOCUMENT:
    case TiXmlText::TINYXML_DECLARATION:
    case TiXmlText::TINYXML_TEXT:
    case TiXmlText::TINYXML_UNKNOWN:
    case TiXmlText::TINYXML_COMMENT:
    {
        break;
    }

    case TiXmlText::TINYXML_ELEMENT:
    {
        if(pNode->Value() == strNodeName)
        {
            if(!strNodeAttrName.empty())
            {
                TiXmlElement * pElement = pNode->ToElement();
                TiXmlAttribute *pAttr = pElement->FirstAttribute();

                do
                {
                    if(pAttr->Name() == strNodeAttrName && pAttr->Value() == strNodeAttrValue)
                    {
                        return pNode;
                    }
                }
                while((pAttr = pAttr->Next()) != nullptr);
            }
            else
            {
                return pNode;
            }
        }
        else
        {
            //循环访问它的每一个元素
            for(pChildNode = pNode->FirstChild(); pChildNode != nullptr; pChildNode = pChildNode->NextSibling())
            {
                pSelectedNode = selectChildNode(pChildNode, strNodeName, strNodeAttrName, strNodeAttrValue);
                if(pSelectedNode != nullptr)
                {
                    return pSelectedNode;
                }
            }
        }
    }

    default:
    {
        break;
    }

    }

    return nullptr;
}













